package com.unitd.frame.springweb.handler;

import com.alibaba.fastjson.JSON;
import com.unitd.frame.comm.exception.BizException;
import com.unitd.frame.comm.exception.SysRunTimeException;
import com.unitd.frame.comm.utils.CharsetUtils;
import com.unitd.frame.comm.utils.StreamUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @desc 自定义的异常异常处理器, 用于处理抛出自定义的系统运行时异常时做出相应处理
 * @filename SysRunTimeExceptionHandler.java
 * @copyright www.unitd.com
 * @author Hudan
 * @version 1.0
 * @date 2017/3/8
 */
@Component
public class SysRunTimeExceptionHandler extends SimpleMappingExceptionResolver {
	private Logger logger = LoggerFactory.getLogger(getClass());

	@Override
	public ModelAndView resolveException(HttpServletRequest request,
										 HttpServletResponse response, Object handler, Exception e) {
		Map<String, Object> errData = new HashMap<>(1);

		try {
			// 如果抛出的是系统自定义的异常则直接转换
			if(e instanceof AuthenticationException || e instanceof UnauthorizedException) {
				return new ModelAndView("error/403", errData);
			} else if(e instanceof BindException || e instanceof ConstraintViolationException || e instanceof ValidationException) {
				return new ModelAndView("error/500", errData);
			}
			if (e instanceof SysRunTimeException) {
				errData.put("code", ((SysRunTimeException) e).getCode());
				errData.put("msg", e.getMessage());
			} else if (e instanceof BizException) {
					errData.put("code", 500);
					errData.put("msg", e.getMessage());
			} else if (e instanceof DuplicateKeyException) {
				errData.put("code", 500);
				errData.put("msg", "数据库中已存在该记录");
			} else if (e instanceof AuthorizationException) {
				errData.put("code", 403);
				errData.put("msg", "没有权限，请联系管理员授权");
			} else {
				errData.put("code", 500);
				errData.put("msg", "程序运行出现异常:" +e.getMessage());
			}
			// 记录异常日志
			logger.error(e.getMessage(), e);

			String viewName = determineViewName(e, request);
			// JSP/VM 格式返回
			if (viewName != null) {
				boolean isAsync = (request.getHeader("accept").contains("application/json")
						|| (request.getHeader("X-Requested-With") != null
						&& request.getHeader("X-Requested-With").contains("XMLHttpRequest")));
				if (!isAsync) {
					// 如果不是异步请求
					Integer statusCode = determineStatusCode(request, viewName);
					if (statusCode != null) {
						applyStatusCodeIfPossible(request, response, statusCode);
					}
					return getModelAndView(viewName, e, request);
				} else {
					// JSON格式返回
					try {
						response.setContentType("application/json;charset=utf-8");
						response.setCharacterEncoding("utf-8");
						StreamUtils.writeData(JSON.toJSONString(errData).getBytes(CharsetUtils.UTF_8), response.getOutputStream());
					} catch (IOException ex) {
						logger.error("SysRunTimeExceptionHandler 异常处理返回json数据失败", e);
						e.printStackTrace();
					}
					return null;
				}
			}
		} catch (Exception ex) {
			logger.error("SysRunTimeExceptionHandler 异常处理失败", e);
		}
		return new ModelAndView("error/500", errData);
	}
}